#include "BMPReadWrite.h"
#include "Containers/Containers.h"


#include <stdio.h>

#include "Output/Console.h"


bool WH::ReadBMP(const SPath &InFilePath,TVector<uint8_t> &OutData, ETextureFormat &OutFormat, uint64_t &OutWidth, uint64_t &OutHeight, uint64_t &OutPitch)
{
    
    std::ifstream File(InFilePath.GetLowLevel());
    if (!File.is_open())
    {
        WH::PrintLine(U"无法打开文件: {}", InFilePath.ToString());
        return false;
    }

    //Read header
    //FileHeader 
    char8_t Signature[2];
    uint32_t FileSize;
    uint32_t Reserved;
    uint32_t DataOffset;
    

    //InfoHeader     
    uint32_t HeaderSize;
    int32_t Width;
    int32_t Height;
    uint16_t Planes;
    uint16_t BitsPerPixel;
    uint32_t Compression;
    uint32_t ImageSize;
    int32_t XPixelsPerMeter;
    int32_t YPixelsPerMeter;
    uint32_t ColorsUsed;
    uint32_t ImportantColors;
    
    File.read((char*)Signature, 2);
    File.read((char*)&FileSize, 4);
    File.read((char*)&Reserved, 4);
    File.read((char*)&DataOffset, 4);

    File.read((char*)&HeaderSize, 4);
    File.read((char*)&Width, 4);
    File.read((char*)&Height, 4);
    File.read((char*)&Planes, 2);
    File.read((char*)&BitsPerPixel, 2);
    File.read((char*)&Compression, 4);
    File.read((char*)&ImageSize, 4);
    File.read((char*)&XPixelsPerMeter, 4);
    File.read((char*)&YPixelsPerMeter, 4);
    File.read((char*)&ColorsUsed, 4);
    File.read((char*)&ImportantColors, 4);

    // fread(Signature, 1, 2, File);
    // fread(&FileSize, 1, 4, File);
    // fread(&Reserved, 1, 4, File);
    // fread(&DataOffset, 1, 4, File);

    // fread(&HeaderSize, 1, 4, File);
    // fread(&Width, 1, 4, File);
    // fread(&Height, 1, 4, File);
    // fread(&Planes, 1, 2, File);
    // fread(&BitsPerPixel, 1, 2, File);
    // fread(&Compression, 1, 4, File);
    // fread(&ImageSize, 1, 4, File);
    // fread(&XPixelsPerMeter, 1, 4, File);
    // fread(&YPixelsPerMeter, 1, 4, File);
    // fread(&ColorsUsed, 1, 4, File);
    // fread(&ImportantColors, 1, 4, File);

    //Read width and height
    OutWidth = Width;
    OutHeight = Height;
    bool bIsUpsideDown = Height > 0;
    uint64_t FilePitch = ((OutWidth * BitsPerPixel + 31) / 32) * 4;

    //color table
    // uint8_t ColorTable[1024]; // 256 * 4(Blue, Green, Red, Reserved)
    // fread(ColorTable, 1, 1024, File);

    if (BitsPerPixel == 32)
    {
        OutPitch=FilePitch;
        OutFormat = ETextureFormat::R8G8B8A8;
        OutData.Resize(OutPitch * OutHeight);
        
        TVector<uint8_t> Line;
        Line.Resize(FilePitch); 
        if(bIsUpsideDown)
        {
            for (uint64_t y = 0; y < OutHeight; y++)
            {
                File.read((char*)Line.Data(), FilePitch);
                //fread(Line.Data(), 1, FilePitch, File);
                for (uint64_t x = 0; x < OutWidth; x++)
                {
                    int64_t Offset = (OutHeight - y - 1) * OutPitch + x * 4;

                    OutData[Offset + 0] /*R*/ = Line[x * 4 + 3];
                    OutData[Offset + 1] /*G*/= Line[x * 4 + 2];
                    OutData[Offset + 2] /*B*/= Line[x * 4 + 1];
                    OutData[Offset + 3] /*A*/= Line[x * 4 + 0];
                }
            }

        }
        else
        {
            for (uint64_t y = 0; y < OutHeight; y++)
            {
                File.read((char*)Line.Data(), FilePitch);
                //fread(Line.Data(), 1, FilePitch, File);
                for (uint64_t x = 0; x < OutWidth; x++)
                {
                    OutData[y * OutPitch + x * 4 + 0] = Line[x * 4 + 3];
                    OutData[y * OutPitch + x * 4 + 1] = Line[x * 4 + 2];
                    OutData[y * OutPitch + x * 4 + 2] = Line[x * 4 + 1];
                    OutData[y * OutPitch + x * 4 + 3] = Line[x * 4 + 0];
                }
            }
        }
    }
    else if (BitsPerPixel == 24)
    {
        OutPitch=OutWidth * 4;
        OutFormat = ETextureFormat::R8G8B8A8;
        OutData.Resize(OutPitch * OutHeight);

        //convert 24bit to 32bit
        TVector<uint8_t> Line;
        Line.Resize(FilePitch);

        if(bIsUpsideDown)
        {
            for (uint64_t y = 0; y < OutHeight; y++)
            {
                File.read((char*)Line.Data(), FilePitch);
                //fread(Line.Data(), 1, FilePitch, File);
                for (uint64_t x = 0; x < OutWidth; x++)
                {
                    int64_t Offset = (OutHeight - y - 1) * OutPitch + x * 4;

                    OutData[Offset + 0] /*R*/ = Line[x * 3 + 2];
                    OutData[Offset + 1] /*G*/= Line[x * 3 + 1];
                    OutData[Offset + 2] /*B*/= Line[x * 3 + 0];
                    OutData[Offset + 3] /*A*/= 0xFF;
                }
            }
        }
        else
        {
            for (uint64_t y = 0; y < OutHeight; y++)
            {
                File.read((char*)Line.Data(), FilePitch);
                //fread(Line.Data(), 1, FilePitch, File);
                for (uint64_t x = 0; x < OutWidth; x++)
                {
                    OutData[y * OutPitch + x * 4 + 0] = Line[x * 3 + 2];
                    OutData[y * OutPitch + x * 4 + 1] = Line[x * 3 + 1];
                    OutData[y * OutPitch + x * 4 + 2] = Line[x * 3 + 0];
                    OutData[y * OutPitch + x * 4 + 3] = 0xFF;
                }
            }
        }

    }

    else
    {
        WH::PrintLine(U"Unsupported BMP format: {}", BitsPerPixel);
        return false;
    }



    //fclose(File);
    return true;


}